package icu.javayanglei.file.util

import cn.hutool.core.exceptions.UtilException
import cn.hutool.core.io.FileUtil
import cn.hutool.core.io.IoUtil
import cn.hutool.core.util.CharsetUtil
import cn.hutool.core.util.ObjectUtil
import cn.hutool.core.util.StrUtil
import cn.hutool.core.util.URLUtil
import jakarta.servlet.ServletOutputStream
import jakarta.servlet.http.HttpServletResponse
import java.io.BufferedInputStream
import java.io.File
import java.io.IOException
import java.io.InputStream

class ServletUtil {
    companion object {
        /**
         * 返回数据给客户端
         *
         * @param response 响应对象[HttpServletResponse]
         * @param in       需要返回客户端的内容
         */
        fun write(response: HttpServletResponse, `in`: InputStream?) {
            write(response, `in`, IoUtil.DEFAULT_BUFFER_SIZE)
        }

        /**
         * 返回数据给客户端
         *
         * @param response   响应对象[HttpServletResponse]
         * @param in         需要返回客户端的内容
         * @param bufferSize 缓存大小
         */
        fun write(response: HttpServletResponse, `in`: InputStream?, bufferSize: Int) {
            var out: ServletOutputStream? = null
            try {
                out = response.outputStream
                IoUtil.copy(`in`, out, bufferSize)
            } catch (e: IOException) {
                throw UtilException(e)
            } finally {
                IoUtil.close(out)
                IoUtil.close(`in`)
            }
        }

        /**
         * 返回文件给客户端
         *
         * @param response 响应对象[HttpServletResponse]
         * @param file     写出的文件对象
         * @since 4.1.15
         */
        fun write(response: HttpServletResponse, file: File) {
            val fileName = file.name
            val contentType = ObjectUtil.defaultIfNull(FileUtil.getMimeType(fileName), "application/octet-stream")
            var `in`: BufferedInputStream? = null
            try {
                `in` = FileUtil.getInputStream(file)
                write(response, `in`, contentType, fileName)
            } finally {
                IoUtil.close(`in`)
            }
        }

        /**
         * 返回数据给客户端
         *
         * @param response    响应对象[HttpServletResponse]
         * @param in          需要返回客户端的内容
         * @param contentType 返回的类型，可以使用[FileUtil.getMimeType]获取对应扩展名的MIME信息
         *
         *  * application/pdf
         *  * application/vnd.ms-excel
         *  * application/msword
         *  * application/vnd.ms-powerpoint
         *
         * docx、xlsx 这种 office 2007 格式 设置 MIME;网页里面docx 文件是没问题，但是下载下来了之后就变成doc格式了
         * 参考：[https://my.oschina.net/shixiaobao17145/blog/32489](https://my.oschina.net/shixiaobao17145/blog/32489)
         *
         *  * MIME_EXCELX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
         *  * MIME_PPTX_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
         *  * MIME_WORDX_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
         *  * MIME_STREAM_TYPE = "application/octet-stream;charset=utf-8"; #原始字节流
         *
         * @param fileName    文件名，自动添加双引号
         * @since 4.1.15
         */
        fun write(response: HttpServletResponse, `in`: InputStream?, contentType: String?, fileName: String?) {
            val charset = ObjectUtil.defaultIfNull(response.characterEncoding, CharsetUtil.UTF_8)
            val encodeText = URLUtil.encodeAll(fileName, CharsetUtil.charset(charset))
            response.setHeader(
                "Content-Disposition",
                StrUtil.format("attachment;filename=\"{}\";filename*={}''{}", encodeText, charset, encodeText)
            )
            response.contentType = contentType
            write(response, `in`)
        }
    }
}
